import Glibc

class Timer {
    private let CLOCK_REALTIME = 0
    private var start_timespec = timespec()
    private var end_timespec = timespec()
    private var time_spec = timespec()
    func start() {
        clock_gettime(Int32(CLOCK_REALTIME),&start_timespec)
    }
    
    func stop() -> Double {
        clock_gettime(Int32(CLOCK_REALTIME),&end_timespec)
        let start_time = Double(start_timespec.tv_sec * 1_000_000 + start_timespec.tv_nsec / 1_000)
        let end_time = Double(end_timespec.tv_sec * 1_000_000 + end_timespec.tv_nsec / 1_000)
        let time = end_time - start_time
        return time / 1_000
    }
    func getTime() -> Double {
        clock_gettime(Int32(CLOCK_REALTIME),&time_spec)
        return Double(time_spec.tv_sec * 1_000_000 + time_spec.tv_nsec / 1_000)
    }
}

let timer = Timer()

let width = 60

let aluString = "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG" +
    "GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA" +
    "CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT" +
    "ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA" +
    "GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG" +
    "AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC" +
"AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA"
var alu = aluString.utf8CString.map({ UInt8($0) })
_ = alu.popLast()
_ = alu.popLast()

func repeatFasta(geneLength: Int, buffer: inout [Int], gene2: inout [Int]) -> Int {
    var pos = 0
    var rpos = 0
    var cnt = 500000
    var lwidth = width
    while cnt > 0 {
        if pos + lwidth > buffer.count {
            pos = 0
        }
        if rpos + lwidth > geneLength {
            rpos = rpos % geneLength
        }
        if cnt < lwidth {
            lwidth = cnt
        }
        
        for i in 0..<lwidth {
            buffer[pos + i] = gene2[rpos + i];
        }

        buffer[pos+lwidth] = 10
        pos += lwidth + 1
        rpos += lwidth
        cnt -= lwidth
    }
    if pos > 0 && pos < buffer.count {
        buffer[pos] = 10
    } else if pos == buffer.count {
        buffer[0] = 10
    }
    var result = 0
    for i in 0..<buffer.count {
        result += buffer[i]
    }
    return result
}

func runFasta1()->Int{
    let bufferSize = 256 * 1024
    let geneLength = alu.count
    var buffer = [Int](repeating: 10, count: bufferSize)
    var gene2 = [Int](repeating: 10, count: (2 * geneLength))
	for i in 0..<gene2.count {
		gene2[i] = Int(alu[i % geneLength]);
	}
    var res = 0
    timer.start()
    for _ in 0..<500 {
        res += repeatFasta(geneLength: geneLength, buffer: &buffer, gene2: &gene2)
    }
    let time = timer.stop()
    print(res)
    print("Array Access - RunFastaRepeat:\t" + String(time) + "\tms");
    return  Int(time) 
}
_ = runFasta1()
